﻿/*************************************************
taurus Tcp协议 Socket核心类
author：Daixiwei
**************************************************/
using System;
using System.Net;
using System.Net.Sockets;
using System.Security;
using System.Threading;

namespace taurus.client
{
    class SocketUdp : ISocket
    {
        private const int READ_BUFFER_SIZE = 0x1000;
        private byte[] _byteBuffer = new byte[READ_BUFFER_SIZE];

        private UdpClient _connection;
        private int _udpPort;
        private IPEndPoint _remoteEP;
        private readonly object _syncer = new object();

        public SocketUdp(SocketEngine npeer,int udpPort) : base(npeer)
        {
            _udpPort = udpPort;
        }

        public override bool connect()
        {
            if (!base.connect())
            {
                return false;
            }
            else
            {
                state = SocketState.Connecting;
                connectThread();
                return true;
            }
        }

        private void connectThread()
        {
            try
            {
                IPAddress ipAddress = ISocket.getIpAddress(serverAddress);
                if (ipAddress == null)
                {
                    throw new ArgumentException("Invalid IPAddress. Address: " + serverAddress);
                }
                if (ipAddress.AddressFamily != AddressFamily.InterNetwork && ipAddress.AddressFamily != AddressFamily.InterNetworkV6)
                {
                    throw new ArgumentException(string.Format("AddressFamily '{0}' not supported. Address: {1}", ipAddress.AddressFamily, serverAddress));
                }
                _connection = new UdpClient(ipAddress.AddressFamily);
                _connection.Connect(ipAddress, _udpPort);
                _remoteEP = new IPEndPoint(ipAddress, 0);
                state = SocketState.Connected;
                _engine.enqueueStatusCallback(SocketCode.UDPConnect);
            }
            catch (Exception ex)
            {
                Logger.error("Connection error", ex);
                handleException(SocketCode.UDPException);
                return;
            }
            var _thrSocketReader = new Thread(new ThreadStart(__Read));
            _thrSocketReader.IsBackground = true;
            _thrSocketReader.Start();
        }

       

        public override bool disconnect()
        {
            if (state == SocketState.Disconnected) return false;
            state = SocketState.Disconnecting;
            lock (_syncer)
            {
                if (_connection != null)
                {
                    try
                    {
                        _connection.Close();
                    }
                    catch (Exception ex)
                    {
                        Logger.error("Disconnect error", ex);
                    }
                    _connection = null;
                }
            }
            state = SocketState.Disconnected;
            return true;
        }

        public override bool send(byte[] data)
        {
            return __WriteSocket(data);
        }


        private bool __WriteSocket(byte[] buf)
        {
            if (_connection==null || state != SocketState.Connected)
            {
                Logger.error("Trying to write to disconnected socket");
                return false;
            }
            else
            {
                try
                {
                    _connection.Send(buf,buf.Length);
                }
                catch (Exception exception2)
                {
                    Logger.error("General error writing to socket", exception2);
                    handleException(SocketCode.SendError);
                    return false;
                }
            }
            return true;
        }


        private void __Read()
        {

            while (state == SocketState.Connected)
            {
                try
                {
                    try
                    {
                        _byteBuffer = _connection.Receive(ref _remoteEP);
                        if (_byteBuffer != null && _byteBuffer.Length != 0)
                        {
                            __HandleBinaryData(_byteBuffer, _byteBuffer.Length);
                        }
                    }
                    catch (SocketException ex)
                    {
                        if (state != SocketState.Disconnecting && state > SocketState.Disconnected && ex.SocketErrorCode == SocketError.WouldBlock)
                        {
                            continue; 
                        }
                        throw;
                    }

                }
                catch (Exception ex4)
                {
                    if (state != SocketState.Disconnecting && state != SocketState.Disconnected)
                    {
                        Logger.error("Receiving Exception: ", ex4);
                        base.handleException(SocketCode.UDPException);
                    }
                }
            }

            this.disconnect();

        }

        private void __HandleBinaryData(byte[] buf, int size)
        {
            //byte[] dst = new byte[size];
            //Buffer.BlockCopy(buf, 0, dst, 0, size);
            ByteArray array = new ByteArray(buf);
            _engine._packetHandler.onDataRead(array);
        }
    }
}
